/* durecore_shmem.c */
/* 定义双核的共享内存, 这份代码被两个工程同时编译 */
#include "shmem.h"

/* 指定在0x2002_8000开始的 32KB字节的内存*/
#pragma location = 0x20028000
__root volatile uint32_t shmem_words[SHMEM_WORD_NUM]; /* 初始化为0. */
//__no_init volatile uint32_t shmem_words[SHMEM_WORD_LENGTH]; /* 不初始化. */

void shmem_wait_core_events(uint32_t core_id, uint32_t events)
{
	/* wait for flag. */
    while (events != (shmem_words[SHMEM_CORE0_STAT_REG_IDX + core_id] & events) )
    {
    }

    /* clear events. */
    shmem_words[SHMEM_CORE0_STAT_REG_IDX + core_id] &= ~events;
}

void shmem_set_core_events(uint32_t core_id, uint32_t events)
{
	shmem_words[SHMEM_CORE0_STAT_REG_IDX + core_id] |= events;
}

/* for core1. */
void shmem_fifo_init(uint32_t fifo_id)
{
    uint32_t fifo_base_offset = fifo_id << 4u; /* x16. */

    shmem_words[fifo_base_offset + SHMEM_FIFO0_LOCK_REG_IDX]  = 0;
    shmem_words[fifo_base_offset + SHMEM_FIFO0_WRITE_REG_IDX] = 0;
    shmem_words[fifo_base_offset + SHMEM_FIFO0_READ_REG_IDX]  = 0;
    shmem_words[fifo_base_offset + SHMEM_FIFO0_COUNT_REG_IDX] = 0;
}

/* for core 1. */
uint32_t shmem_fifo_pop(uint32_t fifo_id)
{
    uint32_t dat;
    uint32_t fifo_base_offset = fifo_id << 4u; /* x16. */

    /* wait while the fifo is locked. */
    while (shmem_words[fifo_base_offset + SHMEM_FIFO0_LOCK_REG_IDX] == 1)
    {
        /* 此处注意, 不能一直占空总线带宽查, 否则会延缓释放锁的访问. */
        for (uint32_t i = 0u; i < 10u; i++)  asm("nop");
    }

    /* lock the fifo */
    shmem_words[fifo_base_offset + SHMEM_FIFO0_LOCK_REG_IDX] = 1;

    if ( shmem_words[fifo_base_offset + SHMEM_FIFO0_COUNT_REG_IDX] == 0)
    {
        dat = 0; /* empty. */
    }
    else
    {
        dat = shmem_words[
                  fifo_base_offset
                + SHMEM_FIFO0_BASE_REG_IDX
                + shmem_words[fifo_base_offset + SHMEM_FIFO0_READ_REG_IDX]];
        shmem_words[fifo_base_offset + SHMEM_FIFO0_COUNT_REG_IDX]--;
        shmem_words[fifo_base_offset + SHMEM_FIFO0_READ_REG_IDX] =
                (shmem_words[fifo_base_offset + SHMEM_FIFO0_READ_REG_IDX]+1) % SHMEM_FIFO0_OFFSET_NUM;
    }

    /* unlock the fifo */
    shmem_words[fifo_base_offset + SHMEM_FIFO0_LOCK_REG_IDX] = 0;

    return dat;
}

bool shmem_fifo_push(uint32_t fifo_id, uint32_t dat)
{
    bool succ = false;
    uint32_t fifo_base_offset = fifo_id << 4u;

    while (shmem_words[fifo_base_offset + SHMEM_FIFO0_LOCK_REG_IDX] == 1)
    {
        /* 此处注意, 不能一直占空总线带宽查, 否则会延缓释放锁的访问. */
        for (uint32_t i = 0u; i < 10u; i++)  asm("nop");
    }

    /* lock the fifo */
    shmem_words[fifo_base_offset + SHMEM_FIFO0_LOCK_REG_IDX] = 1;

    if (shmem_words[fifo_base_offset + SHMEM_FIFO0_COUNT_REG_IDX] == SHMEM_FIFO0_OFFSET_NUM)
    {
        succ = false; /* fifo full. */
    }
    else
    {
        shmem_words[  fifo_base_offset
                    + SHMEM_FIFO0_BASE_REG_IDX
                    + shmem_words[fifo_base_offset + SHMEM_FIFO0_WRITE_REG_IDX]
                   ] = dat;
        shmem_words[fifo_base_offset + SHMEM_FIFO0_COUNT_REG_IDX]++;
        shmem_words[fifo_base_offset + SHMEM_FIFO0_WRITE_REG_IDX] =
            (shmem_words[fifo_base_offset + SHMEM_FIFO0_WRITE_REG_IDX]+1) % SHMEM_FIFO0_OFFSET_NUM;
        succ = true;
    }

    /* unlock the fifo */
    shmem_words[fifo_base_offset + SHMEM_FIFO0_LOCK_REG_IDX] = 0;

    return succ;
}

/* EOF. */

